package com.wwj.study.proxy.study;

import com.wwj.study.proxy.teacher.GPInvocationHandler;

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * Created by lenovo on 2018/11/18.
 */
public class WProxy{

    private static String ln="\n\r";

    public static Object newProxyInstance(WClassLoader wClassLoader, Class<?>[] interfaces, WInvocationHandler in) throws Exception {
        //1,创建java类
        String strJava= generageJava(interfaces);

        //2.生成java文件
        String filePath=WProxy.class.getResource("").getPath();
        System.out.println(filePath);
        //文件路径
        File file =new File(filePath+"$Proxy0.java");
        //文件流
        FileWriter fileWriter=new FileWriter(file);
        //写入文件
        fileWriter.write(strJava);
        //刷新文件
        fileWriter.flush();
        //关闭文件流
        fileWriter.close();

        //3、把生成的.java文件编译成.class文件
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        StandardJavaFileManager manage = compiler.getStandardFileManager(null, null, null);
        Iterable iterable = manage.getJavaFileObjects(file);

        JavaCompiler.CompilationTask task = compiler.getTask(null, manage, null, null, null, iterable);
        task.call();
        manage.close();

        //4、编译生成的.class文件加载到JVM中来
        Class proxyClass = wClassLoader.findClass("$Proxy0");
        Constructor c = proxyClass.getConstructor(WInvocationHandler.class);

        //5.实例化对象返回  WInvocationHandler 需要做为参数传入

        return c.newInstance(in);
    }

    private static String generageJava(Class<?>[] interfaces) {

        StringBuffer sb = new StringBuffer();
        sb.append("package com.wwj.study.proxy.study;" + ln);
        sb.append("import com.wwj.study.proxy.Person;" + ln);
        sb.append("import java.lang.reflect.Method;" + ln);
        sb.append("public class $Proxy0 implements " + interfaces[0].getName() + "{" + ln);

        sb.append("WInvocationHandler h;" + ln);

        sb.append("public $Proxy0(WInvocationHandler h) { " + ln);

        sb.append("this.h = h;");

        sb.append("}" + ln);


        for (Method m : interfaces[0].getMethods()) {
            sb.append("public " + m.getReturnType().getName() + " " + m.getName() + "() {" + ln);
            sb.append("try{" + ln);
            sb.append("Method m = " + interfaces[0].getName() + ".class.getMethod(\"" + m.getName() + "\",new Class[]{});" + ln);
            sb.append("this.h.invoke(this,m,null);" + ln);
            sb.append("}catch(Throwable e){" + ln);
            sb.append("e.printStackTrace();" + ln);
            sb.append("}");
            sb.append("}");
        }

        sb.append("}" + ln);

        return sb.toString();
    }
}
